package com.leyou.order.service;

import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.leyou.common.dto.CartDTO;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.pojo.UserInfo;
import com.leyou.common.utils.IdWorker;
import com.leyou.order.client.AddressClient;
import com.leyou.order.client.GoodsClient;
import com.leyou.order.config.PayConfig;
import com.leyou.order.dto.AddressDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.enums.PayState;
import com.leyou.order.interceptor.UserInterceptor;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.mapper.OrderStatusMapper;
import com.leyou.order.pojo.Order;
import com.leyou.order.pojo.OrderDetail;
import com.leyou.order.pojo.OrderStatus;
import com.leyou.order.pojo.Sku;
import com.leyou.order.util.PayHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Slf4j
@Service
public class OrderService {
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper detailMapper;
    @Autowired
    private OrderStatusMapper statusMapper;
    @Autowired
    private GoodsClient goodsClient;
    @Autowired
    private PayHelper payHelper;
    @Autowired
    private PayConfig payConfig;


    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Transactional
    public Long createOrder(OrderDTO orderDTO) {
        //1新增订单
        Order order = new Order();
        //1.1生成orderId编号
        long orderId = idWorker.nextId();
        //1.2基本信息
        order.setOrderId(orderId);
        order.setCreateTime(new Date());
        order.setPaymentType(orderDTO.getPaymentType());
        //1.3用户信息
        UserInfo user = UserInterceptor.get();
        order.setBuyerNick(user.getUsername());
        order.setBuyerRate(false);
        order.setUserId(user.getId());
        //1.4收货人信息
        Long addressId = orderDTO.getAddressId();
        AddressDTO addressDTO = AddressClient.findById(addressId);
        order.setReceiver(addressDTO.getName());
        order.setReceiverAddress(addressDTO.getAddress());
        order.setReceiverCity(addressDTO.getCity());
        order.setReceiverDistrict(addressDTO.getDistrict());
        order.setReceiverMobile(addressDTO.getPhone());
        order.setReceiverState(addressDTO.getState());
        order.setReceiverZip(addressDTO.getZipCode());
        //1.5金额
        //查出所有商品
        Map<Long, Integer> cartsMap = orderDTO.getCarts().stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        Set<Long> skuSet = cartsMap.keySet();
        List<Sku> skus = goodsClient.querySkuByIds(new ArrayList<>(skuSet));
        //准备orderDetail集合
        List<OrderDetail> orderDetails=new ArrayList<>();
        //计算金额
        long totalPay=0;//总金额
        for (Sku sku : skus) {
            totalPay += sku.getPrice() * cartsMap.get(sku.getId());
            //封装orderDetail
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setImage(StringUtils.substringBefore(sku.getImages(),","));
            orderDetail.setNum(cartsMap.get(sku.getId()));
            orderDetail.setOwnSpec(sku.getOwnSpec());
            orderDetail.setPrice(sku.getPrice());
            orderDetail.setSkuId(sku.getId());
            orderDetail.setTitle(sku.getTitle());
            orderDetails.add(orderDetail);
        }
        order.setTotalPay(totalPay);
        //实付金额=总金额+邮费-优惠金额
        Long 优惠金额 = 0L;
        order.setActualPay(totalPay+order.getPostFee()-优惠金额);
        int count = orderMapper.insertSelective(order);//选择性的插入,其他没有的让数据库生成默认的值
        if (count != 1) {
            log.error("创建订单失败,orderId :{}" ,orderId);
            throw new LyException(ExceptionEnum.ORDER_CREATED_FAIL);
        }
        // 2订单详情
        count = detailMapper.insertList(orderDetails);
        if (count != orderDetails.size()) {
            log.error("创建订单详情失败,orderId :{}" ,orderId);
            throw new LyException(ExceptionEnum.ORDER_CREATED_FAIL);
        }
        // 3保存订单状态
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setOrderId(orderId);
        orderStatus.setCreateTime(order.getCreateTime());
        orderStatus.setStatus(OrderStatusEnum.UN_PAY.value());// 初始状态为未付款
        count = statusMapper.insertSelective(orderStatus);
        if (count != 1) {
            log.error("创建订单状态失败,orderId :{}" ,orderId);
            throw new LyException(ExceptionEnum.ORDER_CREATED_FAIL);
        }
        logger.debug("生成订单，订单编号：{}，用户id：{}", orderId, user.getId());
        //减库存 这里用同步的,在一个事务里面 可以回滚前面的
        //两种方式 利用freign是同步调用,利用mq是异步调用
        //分布式事务怎么处理 有三种方案 todo 我们的学习资料没有
        List<CartDTO> carts = orderDTO.getCarts();
        goodsClient.decreaseStock(carts);
        return orderId;
    }

    public Order queryById(Long id) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        if (order==null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        // 查询订单详情
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(id);
        List<OrderDetail> details = detailMapper.select(detail);
        if (CollectionUtils.isEmpty(details)) {
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        order.setOrderDetails(details);

        // 查询订单状态
        OrderStatus orderStatus = statusMapper.selectByPrimaryKey(order.getOrderId());
        if (orderStatus==null) {
            throw new LyException(ExceptionEnum.ORDER_STATUS_NOT_FOUND);
        }
        order.setOrderStatus(orderStatus);
        return order;
    }

    public String generateUrl(Long orderId) {
        Order order = queryById(orderId);
        //判断订单的状态
        Integer status = order.getOrderStatus().getStatus();
        if (status != OrderStatusEnum.UN_PAY.value()) {
            throw new LyException(ExceptionEnum.ORDER_STATUS_ERROR);
        }
        OrderDetail orderDetail = order.getOrderDetails().get(0);
        return payHelper.createPayUrl(orderId,order.getActualPay(),orderDetail.getTitle());
    }

    public void handlerNotify(Map<String, String> result) {
        //数据校验
        if (WXPayConstants.FAIL.equals(result.get("return_code"))) {
            log.error("微信下单通信失败,原因：{}", result.get("return_msg"));
            throw new LyException(ExceptionEnum.WEIXIN_PAY_FAIL);
        }
        if (WXPayConstants.FAIL.equals(result.get("result_code"))) {
            log.error("微信下单业务失败,错误码：{},错误原因:{}", result.get("error_code"), result.get("error_code_des"));
            throw new LyException(ExceptionEnum.WEIXIN_PAY_FAIL);
        }
        //签名验证
        try {
            String sign1 = WXPayUtil.generateSignature(result, payConfig.getKey(), WXPayConstants.SignType.HMACSHA256);
            String sign2 = WXPayUtil.generateSignature(result, payConfig.getKey(), WXPayConstants.SignType.MD5);
            String sign = result.get("sign");
            if(!StringUtils.equals(sign1,sign) && !StringUtils.equals(sign2,sign)){
                throw new LyException(ExceptionEnum.WEIXIN_INVALID_SIGN);
            }
        } catch (Exception e) {
            log.error("微信签名有问题",e);
            throw new LyException(ExceptionEnum.WEIXIN_INVALID_SIGN);
        }
        //校验金额
        String totalFeeStr = result.get("total_fee");
        String orderIdStr = result.get("out_trade_no");
        if (StringUtils.isBlank(totalFeeStr)||StringUtils.isBlank(orderIdStr)) {
            throw new LyException(ExceptionEnum.WEIXIN_INVALID_ORDER_PRAM);
        }
        Long totalFee = Long.valueOf(totalFeeStr);
        Long orderId = Long.valueOf(orderIdStr);
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (totalFee != order.getActualPay()) {
            throw new LyException(ExceptionEnum.WEIXIN_INVALID_ORDER_PRAM);
        }
        //如果到这里,说明数据是合法的
        //修改订单状态
        OrderStatus status = new OrderStatus();
        status.setStatus(OrderStatusEnum.PAYED.value());
        status.setOrderId(orderId);
        status.setPaymentTime(new Date());
        int i = statusMapper.updateByPrimaryKeySelective(status);
        if (i != 1) {
            throw new LyException(ExceptionEnum.UPDATE_ORDER_STATUS_FAIL);
        }
        log.info("订单回调,支付成功,订单编号:{}", orderId);
    }

    public PayState queryOrderStatue(Long orderId) {
        OrderStatus orderStatus = statusMapper.selectByPrimaryKey(orderId);
        Integer status = orderStatus.getStatus();
        if (status != OrderStatusEnum.UN_PAY.value()) {
            return PayState.SUCCESS;//如果已经支付了,那么肯定是已支付了
        }
        //如果未支付,可能是微信还没通知过来或者网络延迟,必须去微信查询真正的结果

        return null;
    }
//
//    public PageResult<Order> queryUserOrderList(Integer page, Integer rows, Integer status) {
//        try {
//            // 分页
//            PageHelper.startPage(page, rows);
//            // 获取登录用户
//            UserInfo user = LoginInterceptor.getLoginUser();
//            // 创建查询条件
//            Page<Order> pageInfo = (Page<Order>) this.orderMapper.queryOrderList(user.getId(), status);
//
//            return new PageResult<>(pageInfo.getTotal(), pageInfo);
//        } catch (Exception e) {
//            logger.error("查询订单出错", e);
//            return null;
//        }
//    }
//
//    @Transactional
//    public Boolean updateStatus(Long id, Integer status) {
//        OrderStatus record = new OrderStatus();
//        record.setOrderId(id);
//        record.setStatus(status);
//        // 根据状态判断要修改的时间
//        switch (status) {
//            case 2:
//                record.setPaymentTime(new Date());// 付款
//                break;
//            case 3:
//                record.setConsignTime(new Date());// 发货
//                break;
//            case 4:
//                record.setEndTime(new Date());// 确认收获，订单结束
//                break;
//            case 5:
//                record.setCloseTime(new Date());// 交易失败，订单关闭
//                break;
//            case 6:
//                record.setCommentTime(new Date());// 评价时间
//                break;
//            default:
//                return null;
//        }
//        int count = this.statusMapper.updateByPrimaryKeySelective(record);
//        return count == 1;
//    }

}
